"""
Web
StreamlitWeb
"""

import streamlit as st
import os
import tempfile
import logging
from pathlib import Path
from typing import Optional, Dict, Any
import time

from src.core.video_processor import VideoProcessor
from src.core.transcriber import WhisperTranscriber
from src.core.output_formatter import OutputFormatter
from src.core.utils import format_file_size, format_duration, setup_logging

# 
st.set_page_config(
    page_title="",
    page_icon="",
    layout="wide",
    initial_sidebar_state="expanded"
)

# 
setup_logging('INFO')
logger = logging.getLogger(__name__)

class WebApp:
    """Web"""
    
    def __init__(self):
        self.video_processor = VideoProcessor()
        self.transcriber = None
        self.formatter = OutputFormatter()
        
        # session state
        if 'processing' not in st.session_state:
            st.session_state.processing = False
        if 'result' not in st.session_state:
            st.session_state.result = None
        if 'video_info' not in st.session_state:
            st.session_state.video_info = None
    
    def render_header(self):
        """"""
        st.title(" ")
        st.markdown("---")
        
        col1, col2, col3 = st.columns(3)
        with col1:
            st.metric("", "", "")
        with col2:
            st.metric("", "", "")
        with col3:
            st.metric("", "", "MIT")
    
    def render_sidebar(self):
        """"""
        st.sidebar.header(" ")
        
        # Whisper
        model_options = {
            'tiny': 'Tiny (39MB) - ',
            'base': 'Base (74MB) - ',
            'small': 'Small (244MB) - ',
            'medium': 'Medium (769MB) - ',
            'large': 'Large (1550MB) - '
        }
        
        selected_model = st.sidebar.selectbox(
            " Whisper",
            options=list(model_options.keys()),
            index=1,  # base
            format_func=lambda x: model_options[x],
            help=""
        )
        
        # 
        language_options = {
            'auto': ' ',
            'zh': ' ',
            'en': ' ',
            'ja': ' ',
            'ko': ' ',
            'fr': ' ',
            'de': ' ',
            'es': ' ',
            'ru': ' '
        }
        
        selected_language = st.sidebar.selectbox(
            " ",
            options=list(language_options.keys()),
            format_func=lambda x: language_options[x],
            help=""
        )
        
        # 
        format_options = {
            'txt': '  (.txt)',
            'srt': ' SRT (.srt)',
            'vtt': ' WebVTT (.vtt)',
            'json': ' JSON (.json)',
            'tsv': ' TSV (.tsv)'
        }
        
        selected_formats = st.sidebar.multiselect(
            " ",
            options=list(format_options.keys()),
            default=['txt', 'srt'],
            format_func=lambda x: format_options[x],
            help=""
        )
        
        # 
        with st.sidebar.expander(" "):
            chunk_duration = st.slider(
                "",
                min_value=300,
                max_value=1800,
                value=600,
                step=300,
                help=""
            )
            
            device = st.selectbox(
                "",
                options=['auto', 'cpu', 'cuda'],
                help="auto"
            )
            
            cleanup_temp = st.checkbox(
                "",
                value=True,
                help=""
            )
        
        return {
            'model': selected_model,
            'language': selected_language if selected_language != 'auto' else None,
            'formats': selected_formats,
            'chunk_duration': chunk_duration,
            'device': device if device != 'auto' else None,
            'cleanup_temp': cleanup_temp
        }
    
    def render_file_upload(self):
        """"""
        st.header(" ")
        
        uploaded_file = st.file_uploader(
            "",
            type=['mp4', 'avi', 'mkv', 'mov', 'wmv', 'flv', 'webm', 'm4v', 
                  'mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a'],
            help=""
        )
        
        if uploaded_file is not None:
            # 
            file_size = len(uploaded_file.getvalue())
            st.success(f" : {uploaded_file.name} ({format_file_size(file_size)})")
            
            # 
            with tempfile.NamedTemporaryFile(delete=False, suffix=Path(uploaded_file.name).suffix) as tmp_file:
                tmp_file.write(uploaded_file.getvalue())
                temp_path = tmp_file.name
            
            # 
            try:
                video_info = self.video_processor.get_video_info(temp_path)
                if video_info:
                    st.session_state.video_info = video_info
                    st.session_state.video_info['temp_path'] = temp_path
                    self.display_video_info(video_info)
                    return temp_path
            except Exception as e:
                st.error(f" : {e}")
                os.unlink(temp_path)
        
        return None
    
    def display_video_info(self, video_info: Dict[str, Any]):
        """"""
        st.subheader(" ")
        
        col1, col2, col3 = st.columns(3)
        
        with col1:
            st.metric("⏱ ", format_duration(video_info['duration']))
            st.metric(" ", format_file_size(video_info['file_size']))
        
        with col2:
            if 'width' in video_info:
                st.metric(" ", f"{video_info['width']}×{video_info['height']}")
                st.metric(" ", f"{video_info['fps']:.1f} fps")
        
        with col3:
            st.metric(" ", video_info['format_name'])
            if 'sample_rate' in video_info:
                st.metric(" ", f"{video_info['sample_rate']}Hz")
    
    def process_video(self, file_path: str, settings: Dict[str, Any]):
        """"""
        progress_bar = st.progress(0)
        status_text = st.empty()
        
        try:
            # 
            status_text.text(" Whisper...")
            progress_bar.progress(10)
            
            self.transcriber = WhisperTranscriber(
                settings['model'], 
                settings['device']
            )
            
            # 
            status_text.text(" ...")
            progress_bar.progress(20)
            
            audio_path = self.video_processor.extract_audio(file_path)
            temp_files = [audio_path]
            
            # 
            video_info = st.session_state.video_info
            audio_chunks = []
            
            if video_info['duration'] > settings['chunk_duration']:
                status_text.text(" ...")
                progress_bar.progress(30)
                audio_chunks = self.video_processor.split_audio(audio_path, settings['chunk_duration'])
                temp_files.extend(audio_chunks)
            else:
                audio_chunks = [audio_path]
            
            # 
            status_text.text(" ...")
            progress_bar.progress(40)
            
            def update_progress(p, msg):
                progress = 40 + int(p * 0.5)
                progress_bar.progress(progress)
                status_text.text(f" {msg}")
            
            if len(audio_chunks) == 1:
                result = self.transcriber.transcribe_audio(
                    audio_chunks[0], 
                    settings['language'],
                    update_progress
                )
            else:
                chunk_results = self.transcriber.transcribe_chunks(
                    audio_chunks,
                    settings['language'],
                    update_progress
                )
                result = self.transcriber.merge_chunk_results(
                    chunk_results, 
                    settings['chunk_duration']
                )
            
            # 
            status_text.text(" ...")
            progress_bar.progress(90)
            
            st.session_state.result = result
            
            # 
            if settings['cleanup_temp']:
                self.video_processor.cleanup_temp_files(temp_files)
                if 'temp_path' in st.session_state.video_info:
                    os.unlink(st.session_state.video_info['temp_path'])
            
            progress_bar.progress(100)
            status_text.text(" ")
            
            return True
            
        except Exception as e:
            st.error(f" : {e}")
            logger.error(f": {e}")
            return False
    
    def display_results(self, settings: Dict[str, Any]):
        """"""
        if st.session_state.result is None:
            return
        
        result = st.session_state.result
        
        st.header(" ")
        
        # 
        col1, col2, col3 = st.columns(3)
        with col1:
            st.metric(" ", result.get('language', ''))
        with col2:
            st.metric(" ", f"{len(result['text'])} ")
        with col3:
            if 'segments' in result:
                st.metric(" ", len(result['segments']))
        
        # 
        st.subheader(" ")
        st.text_area(
            "",
            value=result['text'],
            height=300,
            help=""
        )
        
        # 
        st.subheader(" ")
        
        col1, col2 = st.columns(2)
        
        for i, fmt in enumerate(settings['formats']):
            try:
                # 
                if fmt == 'txt':
                    content = result['text']
                    mime_type = 'text/plain'
                elif fmt == 'srt':
                    content = self._generate_srt_content(result)
                    mime_type = 'text/plain'
                elif fmt == 'vtt':
                    content = self._generate_vtt_content(result)
                    mime_type = 'text/plain'
                elif fmt == 'json':
                    import json
                    content = json.dumps(result, ensure_ascii=False, indent=2)
                    mime_type = 'application/json'
                elif fmt == 'tsv':
                    content = self._generate_tsv_content(result)
                    mime_type = 'text/tab-separated-values'
                
                # 
                filename = f"transcript.{fmt}"
                
                if i % 2 == 0:
                    with col1:
                        st.download_button(
                            label=f"  {fmt.upper()}",
                            data=content,
                            file_name=filename,
                            mime=mime_type,
                            key=f"download_{fmt}"
                        )
                else:
                    with col2:
                        st.download_button(
                            label=f"  {fmt.upper()}",
                            data=content,
                            file_name=filename,
                            mime=mime_type,
                            key=f"download_{fmt}"
                        )
                        
            except Exception as e:
                st.error(f" {fmt} : {e}")
    
    def _generate_srt_content(self, result: Dict[str, Any]) -> str:
        """SRT"""
        if 'segments' not in result:
            return f"1\n00:00:00,000 --> 99:59:59,999\n{result['text']}\n"
        
        srt_content = ""
        for i, segment in enumerate(result['segments'], 1):
            start_time = self._format_time_srt(segment['start'])
            end_time = self._format_time_srt(segment['end'])
            text = segment['text'].strip()
            
            srt_content += f"{i}\n{start_time} --> {end_time}\n{text}\n\n"
        
        return srt_content
    
    def _generate_vtt_content(self, result: Dict[str, Any]) -> str:
        """VTT"""
        vtt_content = "WEBVTT\n\n"
        
        if 'segments' not in result:
            vtt_content += f"00:00:00.000 --> 99:59:59.999\n{result['text']}\n"
            return vtt_content
        
        for segment in result['segments']:
            start_time = self._format_time_vtt(segment['start'])
            end_time = self._format_time_vtt(segment['end'])
            text = segment['text'].strip()
            
            vtt_content += f"{start_time} --> {end_time}\n{text}\n\n"
        
        return vtt_content
    
    def _generate_tsv_content(self, result: Dict[str, Any]) -> str:
        """TSV"""
        tsv_content = "start\tend\ttext\n"
        
        if 'segments' not in result:
            tsv_content += f"0.000\t999999.999\t{result['text']}\n"
            return tsv_content
        
        for segment in result['segments']:
            start = f"{segment['start']:.3f}"
            end = f"{segment['end']:.3f}"
            text = segment['text'].strip().replace('\t', ' ').replace('\n', ' ')
            tsv_content += f"{start}\t{end}\t{text}\n"
        
        return tsv_content
    
    def _format_time_srt(self, seconds: float) -> str:
        """SRT"""
        from datetime import timedelta
        td = timedelta(seconds=seconds)
        hours, remainder = divmod(td.total_seconds(), 3600)
        minutes, seconds = divmod(remainder, 60)
        milliseconds = int((seconds % 1) * 1000)
        return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d},{milliseconds:03d}"
    
    def _format_time_vtt(self, seconds: float) -> str:
        """VTT"""
        return self._format_time_srt(seconds).replace(',', '.')
    
    def run(self):
        """Web"""
        self.render_header()
        
        # 
        settings = self.render_sidebar()
        
        # 
        file_path = self.render_file_upload()
        
        if file_path and not st.session_state.processing:
            if st.button(" ", type="primary", use_container_width=True):
                st.session_state.processing = True
                st.rerun()
        
        if st.session_state.processing and file_path:
            with st.spinner("..."):
                success = self.process_video(file_path, settings)
                if success:
                    st.session_state.processing = False
                    st.success(" ")
                    st.rerun()
                else:
                    st.session_state.processing = False
        
        # 
        if st.session_state.result:
            self.display_results(settings)
        
        # 
        st.markdown("---")
        st.markdown(
            " ****: "
        )

def main():
    """"""
    app = WebApp()
    app.run()

if __name__ == "__main__":
    main()